<template>
  <div class="app-post-toc">
    <ul class="menu-content">
      <li v-for="(item, key) of cata.menuData" :key="key" :style="menuStyle(item.type)" :class="cata.menuState === item.txt ? `active` : ``">
        <a :href="'#' + item.point" class="tree-list"> {{ item.txt }} </a>
      </li>
    </ul>
  </div>
</template>
<script setup lang="ts">
interface Menu {
  type: string
  txt: string
  offsetTop: number
  point: string
}

const cata = reactive<any>({
  menuData: [],
  menuState: '',
})

/**
 * h1 h2 h3 h4 标签样式
 * @param type
 */
const menuStyle = (type: string) => {
  let style = {}
  if (type === 'H2') style = { 'padding-left': 20 + 'px' }
  if (type === 'H3') style = { 'padding-left': 40 + 'px' }
  if (type === 'H4') style = { 'padding-left': 60 + 'px' }

  return style
}

onMounted(() => {
  componentDidMount()
  window.addEventListener('scroll', onScroll, true)
})

// 重新实现目录的定位
const componentDidMount = () => {
  nextTick(() => {
    getElement(['H1', 'H2', 'H3', 'H4'])
  })
}

/**
 * 获取标题锚点
 * 参数nodeArr 表示需要解析目录内容的标题
 */
const getElement = (nodeArr: string[]) => {
  const nodeInfo: Menu[] = []
  const dom: any = document.querySelector('.markdown-body')

  dom.childNodes.forEach((item: any, key: number) => {
    if (nodeArr.includes(item.nodeName)) {
      nodeInfo.push({
        type: item.nodeName,
        txt: item.innerText,
        offsetTop: item.offsetTop,
        point: `target_${key}`,
      })
      item.setAttribute('id', `target_${key}`)
    }
  })

  cata.menuData = nodeInfo
  cata.menuState = nodeInfo[0].txt
}

/**
 * 监听页面开始滚动
 */
const onScroll = (e: any) => {
  if (!isBrowser()) return

  // 当前页面滚动的距离
  const { scrollTop, clientHeight } = e.target.documentElement || e.target.body
  const scrollHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight)

  // 设置menuState对象默认值第一个标题
  let currentmenu = cata.menuData[0].txt
  for (const item of cata.menuData) {
    if (scrollTop >= item.offsetTop) {
      currentmenu = item.txt
    } else {
      break
    }
  }

  if (currentmenu !== cata.menuState) {
    cata.menuState = currentmenu
  }

  // 如果到底部，就命中最后一个标题
  if (scrollTop + clientHeight >= scrollHeight) {
    cata.menuState = cata.menuData[cata.menuData.length - 1].txt
  }
}
</script>
<style lang="scss">
.app-post-toc {
  max-height: 90vh;
  min-height: 10vh;
  overflow-y: scroll;
  .directory {
    font-size: 18px;
    padding: 20px 20px 0;
  }
  .menu-content {
    width: 100%;
    li {
      &.active {
        position: relative;
        a{
          color: var(--theme-orange);
        }
        &::before {
          content: ' ';
          height: 20px;
          width: 5px;
          background: var(--theme-orange);
          position: absolute;
          left: 0;
          top: 50%;
          border-radius: 0 5px 5px 0;
          transform: translateY(-50%);
        }
      }
    }
    .tree-list {
      display: block;
      font-size: 14px;
      padding: 10px;
      &:hover {
        background-color: #f7f8fa;
        border-radius: 6px;
        color: var(--theme-orange);
      }
    }
    .active {
      position: relative;
      color: var(--theme-orange);
    }
  }
}
</style>
